package ElectricCraft.frames;

import ElectricCraft.misc.PopupMenuWrapper;
import ElectricCraft.model.ChipModel;
import ElectricCraft.model.ModelGroup;

import javax.swing.*;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeSelectionModel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * PackageViewTree class provides ModelPackages editing.
 */
public class PackageViewTree extends JTree {
    private final DefaultTreeModel treeModel;
    private final MainWindow mainWindow;
    private final boolean editable;
    public PackageViewTree(MainWindow mainWindow, boolean editable) {
        super(new PackageViewNode(mainWindow.getPackage()));

        this.mainWindow = mainWindow;
        this.editable = editable;

        treeModel = (DefaultTreeModel)getModel();

        getSelectionModel().setSelectionMode(
                TreeSelectionModel.SINGLE_TREE_SELECTION);

        // TODO: support drag and drop

        initUI();
    }

    private void initUI() {
        createPopupMenu();

        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (getSelectionCount() != 1 || !editable) {
                    return;
                }

                PackageViewNode node = getCurrentNode();

                if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
                    if (node.model != null && editable) {
                        mainWindow.openModel(node.model);
                    }
                }

                if (e.getButton() == MouseEvent.BUTTON3) {
                    if (node.isLeaf()) {
                        modelPopupMenu.show(e.getComponent(), e.getX(), e.getY());
                    } else {
                        groupPopupMenu.show(e.getComponent(), e.getX(), e.getY());
                    }
                }
            }
        });
    }

    private PopupMenuWrapper groupPopupMenu;
    private PopupMenuWrapper modelPopupMenu;

    private void createPopupMenu() {
        modelPopupMenu = new PopupMenuWrapper();
        modelPopupMenu.createItems("Open", "Rename", "Delete");

        modelPopupMenu.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (modelPopupMenu.checkAction(e, "Open")) {
                    PackageViewNode node = getCurrentNode();
                    if (node != null && node.model != null) {
                        mainWindow.openModel(node.model);
                    }
                } else if (modelPopupMenu.checkAction(e, "Rename")) {
                    processRenameModel();
                } else if (modelPopupMenu.checkAction(e, "Delete")) {
                    processDeleteModel();
                }
            }
        });

        groupPopupMenu = new PopupMenuWrapper();
        groupPopupMenu.createItems("New chip model", "New group", "Rename", "Delete");

        groupPopupMenu.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (groupPopupMenu.checkAction(e, "New chip model")) {
                    processNewModel();
                } else if (groupPopupMenu.checkAction(e, "New group")) {
                    processNewGroup();
                } else if (groupPopupMenu.checkAction(e, "Rename")) {
                    processRenameGroup();
                } else if (groupPopupMenu.checkAction(e, "Delete")) {
                    processDeleteGroup();
                }
            }
        });
    }

    public PackageViewNode getCurrentNode() {
        return (PackageViewNode) getSelectionPath().getLastPathComponent();
    }

    private void processNewGroup() {
        PackageViewNode node = getCurrentNode();

        String newGroupName = JOptionPane.showInputDialog(mainWindow.getFrame(), "Name:", "");
        if (newGroupName == null || newGroupName.isEmpty()) {
            return ;
        }

        if (node.group.findGroupByName(newGroupName) != null) {
            JOptionPane.showMessageDialog(mainWindow.getFrame(), "Group with such name already exists");
            return ;
        }

        ModelGroup newGroup = new ModelGroup(newGroupName);
        node.group.groups.add(newGroup);

        node.add(new PackageViewNode(newGroup, null));

        treeModel.nodeStructureChanged(node);
    }

    private void processRenameGroup() {
        PackageViewNode node = getCurrentNode();

        if (node.isRoot()) {
            JOptionPane.showMessageDialog(mainWindow.getFrame(), "Root group cannot be renamed");
            return ;
        }

        String newGroupName = JOptionPane.showInputDialog(mainWindow.getFrame(), "Name:", node.group.name);
        if (newGroupName == null || newGroupName.isEmpty()) {
            return ;
        }

        PackageViewNode parent = (PackageViewNode)node.getParent();
        if (parent.group.findGroupByName(newGroupName) != null) {
            JOptionPane.showMessageDialog(mainWindow.getFrame(), "Group with such name already exists");
            return ;
        }

        node.group.name = newGroupName;

        treeModel.nodeStructureChanged(node);
    }

    private void processDeleteGroup() {
        PackageViewNode node = getCurrentNode();

        if (node.isRoot()) {
            JOptionPane.showMessageDialog(mainWindow.getFrame(), "Root group cannot be deleted");
            return ;
        }

        int res = JOptionPane.showConfirmDialog(
                mainWindow.getFrame(),
                "Are you sure you want to delete this group?",
                "Delete group", JOptionPane.YES_NO_OPTION);

        if (res == JOptionPane.NO_OPTION) {
            return ;
        }

        if (!node.group.groups.isEmpty() || !node.group.models.isEmpty()) {
            res = JOptionPane.showConfirmDialog(
                    mainWindow.getFrame(),
                    "The group is not empty.\nDo you still want to delete it?",
                    "Delete group", JOptionPane.YES_NO_OPTION);

            if (res == JOptionPane.NO_OPTION) {
                return ;
            }
        }

        PackageViewNode parent = (PackageViewNode)node.getParent();
        parent.group.groups.remove(node.group);
        parent.remove(node);

        treeModel.nodeStructureChanged(parent);
    }

    private void processNewModel() {
        PackageViewNode node = getCurrentNode();

        String newName = JOptionPane.showInputDialog(mainWindow.getFrame(), "Name:", "");
        if (newName == null || newName.isEmpty()) {
            return ;
        }

        if (node.group.findModelByName(newName) != null) {
            JOptionPane.showMessageDialog(mainWindow.getFrame(), "Model with such name already exists");
            return ;
        }

        ChipModel newModel = new ChipModel(newName);
        node.group.models.add(newModel);

        node.add(new PackageViewNode(node.group, newModel));

        treeModel.nodeStructureChanged(node);

        mainWindow.openModel(newModel);
    }

    private void processRenameModel() {
        PackageViewNode node = getCurrentNode();

        if (node.model == null) {
            return ;
        }

        String newModelName = JOptionPane.showInputDialog(mainWindow.getFrame(), "Name:", node.model.name);
        if (newModelName == null || newModelName.isEmpty()) {
            return ;
        }

        PackageViewNode parent = (PackageViewNode)node.getParent();
        if (parent.group.findModelByName(newModelName) != null) {
            JOptionPane.showMessageDialog(mainWindow.getFrame(), "Model with such name already exists");
            return ;
        }

        node.model.name = newModelName;
        treeModel.nodeStructureChanged(node);

        mainWindow.updateModelNames();
    }

    private void processDeleteModel() {
        PackageViewNode node = getCurrentNode();

        if (node.model == null) {
            return ;
        }

        int res = JOptionPane.showConfirmDialog(
                mainWindow.getFrame(),
                "Are you sure you want to delete this model?",
                "Delete model", JOptionPane.YES_NO_OPTION);

        if (res == JOptionPane.NO_OPTION) {
            return ;
        }

        PackageViewNode parent = (PackageViewNode)node.getParent();
        parent.group.models.remove(node.model);
        parent.remove(node);

        treeModel.nodeStructureChanged(parent);

        // close editor if it opened
        ChipEditorPane editor = mainWindow.getEditorByModel(node.model);
        if (editor != null) {
            mainWindow.closeEditor(editor);
        }
    }
}
